home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / MAME / src / tilemap.c < prev    next >
C/C++ Source or Header  |  2000-04-23  |  53KB  |  1,742 lines

  1. /* tilemap.c
  2.  
  3. In Progress
  4. -    visibility walk (temporarily broken)
  5. -    nowrap
  6.  
  7. To Do:
  8. -    virtualization for huge tilemaps
  9. -    precompute spans per row (to speed up the low level code)
  10. -    support for unusual tile sizes (8x12, 8x10)
  11. -    screenwise scrolling
  12. -    internal profiling
  13.  
  14.     Usage Notes:
  15.  
  16.     When the videoram for a tile changes, call tilemap_mark_tile_dirty
  17.     with the appropriate tile_index.
  18.  
  19.     In the video driver, follow these steps:
  20.  
  21.     1)    set each tilemap's scroll registers
  22.  
  23.     2)    call tilemap_update for each tilemap.
  24.  
  25.     3)    call palette_init_used_colors.
  26.         mark the colors used by sprites.
  27.         call palette recalc.  If the palette manager has compressed the palette,
  28.             call tilemap_mark_all_pixels_dirty for each tilemap.
  29.  
  30.     4)    call tilemap_render for each tilemap.
  31.  
  32.     5)    call tilemap_draw to draw the tilemaps to the screen, from back to front
  33. */
  34.  
  35. #ifndef DECLARE
  36.  
  37. #include "driver.h"
  38. #include "tilemap.h"
  39.  
  40. #define SWAP(X,Y) {UINT32 temp=X; X=Y; Y=temp; }
  41.  
  42. /***********************************************************************************/
  43. /* some common mappings */
  44.  
  45. UINT32 tilemap_scan_rows( UINT32 col, UINT32 row, UINT32 num_cols, UINT32 num_rows ){
  46.     /* logical (col,row) -> memory offset */
  47.     return row*num_cols + col;
  48. }
  49. UINT32 tilemap_scan_cols( UINT32 col, UINT32 row, UINT32 num_cols, UINT32 num_rows ){
  50.     /* logical (col,row) -> memory offset */
  51.     return col*num_rows + row;
  52. }
  53.  
  54. /*********************************************************************************/
  55.  
  56. static struct osd_bitmap *create_tmpbitmap( int width, int height, int depth ){
  57.     if( Machine->orientation&ORIENTATION_SWAP_XY ) SWAP(width,height);
  58.     return osd_new_bitmap( width,height,depth );
  59. }
  60.  
  61. static struct osd_bitmap *create_bitmask( int width, int height ){
  62.     width = (width+7)/8; /* 8 bits per byte */
  63.     if( Machine->orientation&ORIENTATION_SWAP_XY ) SWAP(width,height);
  64.     return osd_new_bitmap( width,height, 8 );
  65. }
  66.  
  67. /***********************************************************************************/
  68.  
  69. static int mappings_create( struct tilemap *tilemap ){
  70.     int max_memory_offset = 0;
  71.     UINT32 col,row;
  72.     UINT32 num_logical_rows = tilemap->num_logical_rows;
  73.     UINT32 num_logical_cols = tilemap->num_logical_cols;
  74.     /* count offsets (might be larger than num_tiles) */
  75.     for( row=0; row<num_logical_rows; row++ ){
  76.         for( col=0; col<num_logical_cols; col++ ){
  77.             UINT32 memory_offset = tilemap->get_memory_offset( col, row, num_logical_cols, num_logical_rows );
  78.             if( memory_offset>max_memory_offset ) max_memory_offset = memory_offset;
  79.         }
  80.     }
  81.     max_memory_offset++;
  82.     tilemap->max_memory_offset = max_memory_offset;
  83.     /* logical to cached (tilemap_mark_dirty) */
  84.     tilemap->memory_offset_to_cached_index = malloc( sizeof(int)*max_memory_offset );
  85.     if( tilemap->memory_offset_to_cached_index ){
  86.         /* cached to logical (get_tile_info) */
  87.         tilemap->cached_index_to_memory_offset = malloc( sizeof(UINT32)*tilemap->num_tiles );
  88.         if( tilemap->cached_index_to_memory_offset ) return 0; /* no error */
  89.         free( tilemap->memory_offset_to_cached_index );
  90.     }
  91.     return -1; /* error */
  92. }
  93.  
  94. static void mappings_dispose( struct tilemap *tilemap ){
  95.     free( tilemap->cached_index_to_memory_offset );
  96.     free( tilemap->memory_offset_to_cached_index );
  97. }
  98.  
  99. static void mappings_update( struct tilemap *tilemap ){
  100.     int logical_flip;
  101.     UINT32 logical_index, cached_index;
  102.     UINT32 num_cached_rows = tilemap->num_cached_rows;
  103.     UINT32 num_cached_cols = tilemap->num_cached_cols;
  104.     UINT32 num_logical_rows = tilemap->num_logical_rows;
  105.     UINT32 num_logical_cols = tilemap->num_logical_cols;
  106.     for( logical_index=0; logical_index<tilemap->max_memory_offset; logical_index++ ){
  107.         tilemap->memory_offset_to_cached_index[logical_index] = -1;
  108.     }
  109.  
  110.     logerror("log size(%dx%d); cach size(%dx%d)\n",
  111.             num_logical_cols,num_logical_rows,
  112.             num_cached_cols,num_cached_rows);
  113.  
  114.     for( logical_index=0; logical_index<tilemap->num_tiles; logical_index++ ){
  115.         UINT32 logical_col = logical_index%num_logical_cols;
  116.         UINT32 logical_row = logical_index/num_logical_cols;
  117.         int memory_offset = tilemap->get_memory_offset( logical_col, logical_row, num_logical_cols, num_logical_rows );
  118.         UINT32 cached_col = logical_col;
  119.         UINT32 cached_row = logical_row;
  120.         if( tilemap->orientation & ORIENTATION_SWAP_XY ) SWAP(cached_col,cached_row)
  121.         if( tilemap->orientation & ORIENTATION_FLIP_X ) cached_col = (num_cached_cols-1)-cached_col;
  122.         if( tilemap->orientation & ORIENTATION_FLIP_Y ) cached_row = (num_cached_rows-1)-cached_row;
  123.         cached_index = cached_row*num_cached_cols+cached_col;
  124.         tilemap->memory_offset_to_cached_index[memory_offset] = cached_index;
  125.         tilemap->cached_index_to_memory_offset[cached_index] = memory_offset;
  126.     }
  127.     for( logical_flip = 0; logical_flip<4; logical_flip++ ){
  128.         int cached_flip = logical_flip;
  129.         if( tilemap->attributes&TILEMAP_FLIPX ) cached_flip ^= TILE_FLIPX;
  130.         if( tilemap->attributes&TILEMAP_FLIPY ) cached_flip ^= TILE_FLIPY;
  131. #ifndef PREROTATE_GFX
  132.         if( Machine->orientation & ORIENTATION_SWAP_XY ){
  133.             if( Machine->orientation & ORIENTATION_FLIP_X ) cached_flip ^= TILE_FLIPY;
  134.             if( Machine->orientation & ORIENTATION_FLIP_Y ) cached_flip ^= TILE_FLIPX;
  135.         }
  136.         else {
  137.             if( Machine->orientation & ORIENTATION_FLIP_X ) cached_flip ^= TILE_FLIPX;
  138.             if( Machine->orientation & ORIENTATION_FLIP_Y ) cached_flip ^= TILE_FLIPY;
  139.         }
  140. #endif
  141.         if( tilemap->orientation & ORIENTATION_SWAP_XY ){
  142.             cached_flip = ((cached_flip&1)<<1) | ((cached_flip&2)>>1);
  143.         }
  144.         tilemap->logical_flip_to_cached_flip[logical_flip] = cached_flip;
  145.     }
  146. }
  147.  
  148. /***********************************************************************************/
  149.  
  150. struct osd_bitmap *priority_bitmap; /* priority buffer (corresponds to screen bitmap) */
  151. int priority_bitmap_line_offset;
  152.  
  153. static UINT8 flip_bit_table[0x100]; /* horizontal flip for 8 pixels */
  154. static struct tilemap *first_tilemap; /* resource tracking */
  155. static int screen_width, screen_height;
  156. struct tile_info tile_info;
  157.  
  158. enum {
  159.     TILE_TRANSPARENT,
  160.     TILE_MASKED,
  161.     TILE_OPAQUE
  162. };
  163.  
  164. /* the following parameters are constant across tilemap_draw calls */
  165. static struct {
  166.     int clip_left, clip_top, clip_right, clip_bottom;
  167.     int source_width, source_height;
  168.     int dest_line_offset,source_line_offset,mask_line_offset;
  169.     int dest_row_offset,source_row_offset,mask_row_offset;
  170.     struct osd_bitmap *screen, *pixmap, *bitmask;
  171.     UINT8 **mask_data_row;
  172.     UINT8 **priority_data_row;
  173.     int tile_priority;
  174.     int tilemap_priority_code;
  175. } blit;
  176.  
  177. #define MASKROWBYTES(W) (((W)+7)/8)
  178.  
  179. static void memsetbitmask8( UINT8 *dest, int value, const UINT8 *bitmask, int count ){
  180. /* TBA: combine with memcpybitmask */
  181.     for(;;){
  182.         UINT32 data = *bitmask++;
  183.         if( data&0x80 ) dest[0] |= value;
  184.         if( data&0x40 ) dest[1] |= value;
  185.         if( data&0x20 ) dest[2] |= value;
  186.         if( data&0x10 ) dest[3] |= value;
  187.         if( data&0x08 ) dest[4] |= value;
  188.         if( data&0x04 ) dest[5] |= value;
  189.         if( data&0x02 ) dest[6] |= value;
  190.         if( data&0x01 ) dest[7] |= value;
  191.         if( --count == 0 ) break;
  192.         dest+=8;
  193.     }
  194. }
  195.  
  196. static void memcpybitmask8( UINT8 *dest, const UINT8 *source, const UINT8 *bitmask, int count ){
  197.     for(;;){
  198.         UINT32 data = *bitmask++;
  199.         if( data&0x80 ) dest[0] = source[0];
  200.         if( data&0x40 ) dest[1] = source[1];
  201.         if( data&0x20 ) dest[2] = source[2];
  202.         if( data&0x10 ) dest[3] = source[3];
  203.         if( data&0x08 ) dest[4] = source[4];
  204.         if( data&0x04 ) dest[5] = source[5];
  205.         if( data&0x02 ) dest[6] = source[6];
  206.         if( data&0x01 ) dest[7] = source[7];
  207.         if( --count == 0 ) break;
  208.         source+=8;
  209.         dest+=8;
  210.     }
  211. }
  212.  
  213. /***********************************************************************************/
  214.  
  215. static void memcpybitmask16( UINT16 *dest, const UINT16 *source, const UINT8 *bitmask, int count ){
  216.     for(;;){
  217.         UINT32 data = *bitmask++;
  218.         if( data&0x80 ) dest[0] = source[0];
  219.         if( data&0x40 ) dest[1] = source[1];
  220.         if( data&0x20 ) dest[2] = source[2];
  221.         if( data&0x10 ) dest[3] = source[3];
  222.         if( data&0x08 ) dest[4] = source[4];
  223.         if( data&0x04 ) dest[5] = source[5];
  224.         if( data&0x02 ) dest[6] = source[6];
  225.         if( data&0x01 ) dest[7] = source[7];
  226.         if( --count == 0 ) break;
  227.         source+=8;
  228.         dest+=8;
  229.     }
  230. }
  231.  
  232. /***********************************************************************************/
  233.  
  234. #define TILE_WIDTH    8
  235. #define TILE_HEIGHT    8
  236. #define DATA_TYPE UINT8
  237. #define memcpybitmask memcpybitmask8
  238. #define DECLARE(function,args,body) static void function##8x8x8BPP args body
  239. #include "tilemap.c"
  240.  
  241. #define TILE_WIDTH    16
  242. #define TILE_HEIGHT    16
  243. #define DATA_TYPE UINT8
  244. #define memcpybitmask memcpybitmask8
  245. #define DECLARE(function,args,body) static void function##16x16x8BPP args body
  246. #include "tilemap.c"
  247.  
  248. #define TILE_WIDTH    32
  249. #define TILE_HEIGHT    32
  250. #define DATA_TYPE UINT8
  251. #define memcpybitmask memcpybitmask8
  252. #define DECLARE(function,args,body) static void function##32x32x8BPP args body
  253. #include "tilemap.c"
  254.  
  255. #define TILE_WIDTH    8
  256. #define TILE_HEIGHT    8
  257. #define DATA_TYPE UINT16
  258. #define memcpybitmask memcpybitmask16
  259. #define DECLARE(function,args,body) static void function##8x8x16BPP args body
  260. #include "tilemap.c"
  261.  
  262. #define TILE_WIDTH    16
  263. #define TILE_HEIGHT    16
  264. #define DATA_TYPE UINT16
  265. #define memcpybitmask memcpybitmask16
  266. #define DECLARE(function,args,body) static void function##16x16x16BPP args body
  267. #include "tilemap.c"
  268.  
  269. #define TILE_WIDTH    32
  270. #define TILE_HEIGHT    32
  271. #define DATA_TYPE UINT16
  272. #define memcpybitmask memcpybitmask16
  273. #define DECLARE(function,args,body) static void function##32x32x16BPP args body
  274. #include "tilemap.c"
  275.  
  276. /*********************************************************************************/
  277.  
  278. static void mask_dispose( struct tilemap_mask *mask ){
  279.     if( mask ){
  280.         free( mask->data_row );
  281.         free( mask->data );
  282.         osd_free_bitmap( mask->bitmask );
  283.         free( mask );
  284.     }
  285. }
  286.  
  287. static struct tilemap_mask *mask_create( struct tilemap *tilemap ){
  288.     struct tilemap_mask *mask = malloc( sizeof(struct tilemap_mask) );
  289.     if( mask ){
  290.         mask->data = malloc( tilemap->num_tiles );
  291.         mask->data_row = malloc( tilemap->num_cached_rows * sizeof(UINT8 *) );
  292.         mask->bitmask = create_bitmask( tilemap->cached_width, tilemap->cached_height );
  293.         if( mask->data && mask->data_row && mask->bitmask ){
  294.             int row;
  295.             for( row=0; row<tilemap->num_cached_rows; row++ ){
  296.                 mask->data_row[row] = mask->data + row*tilemap->num_cached_cols;
  297.             }
  298.             mask->line_offset = mask->bitmask->line[1] - mask->bitmask->line[0];
  299.             return mask;
  300.         }
  301.     }
  302.     mask_dispose( mask );
  303.     return NULL;
  304. }
  305.  
  306. /***********************************************************************************/
  307.  
  308. static void install_draw_handlers( struct tilemap *tilemap ){
  309.     int tile_width = tilemap->cached_tile_width;
  310.     int tile_height = tilemap->cached_tile_height;
  311.     tilemap->draw = tilemap->draw_opaque = NULL;
  312.     if( Machine->scrbitmap->depth==16 ){
  313.         if( tile_width==8 && tile_height==8 ){
  314.             tilemap->draw = draw8x8x16BPP;
  315.             tilemap->draw_opaque = draw_opaque8x8x16BPP;
  316.         }
  317.         else if( tile_width==16 && tile_height==16 ){
  318.             tilemap->draw = draw16x16x16BPP;
  319.             tilemap->draw_opaque = draw_opaque16x16x16BPP;
  320.         }
  321.         else if( tile_width==32 && tile_height==32 ){
  322.             tilemap->draw = draw32x32x16BPP;
  323.             tilemap->draw_opaque = draw_opaque32x32x16BPP;
  324.         }
  325.     }
  326.     else {
  327.         if( tile_width==8 && tile_height==8 ){
  328.             tilemap->draw = draw8x8x8BPP;
  329.             tilemap->draw_opaque = draw_opaque8x8x8BPP;
  330.         }
  331.         else if( tile_width==16 && tile_height==16 ){
  332.             tilemap->draw = draw16x16x8BPP;
  333.             tilemap->draw_opaque = draw_opaque16x16x8BPP;
  334.         }
  335.         else if( tile_width==32 && tile_height==32 ){
  336.             tilemap->draw = draw32x32x8BPP;
  337.             tilemap->draw_opaque = draw_opaque32x32x8BPP;
  338.         }
  339.     }
  340. }
  341.  
  342. /***********************************************************************************/
  343.  
  344. int tilemap_init( void ){
  345.     UINT32 value, data, bit;
  346.     for( value=0; value<0x100; value++ ){
  347.         data = 0;
  348.         for( bit=0; bit<8; bit++ ) if( (value>>bit)&1 ) data |= 0x80>>bit;
  349.         flip_bit_table[value] = data;
  350.     }
  351.     screen_width = Machine->scrbitmap->width;
  352.     screen_height = Machine->scrbitmap->height;
  353.     first_tilemap = 0;
  354.     priority_bitmap = create_tmpbitmap( screen_width, screen_height, 8 );
  355.     if( priority_bitmap ){
  356.         priority_bitmap_line_offset = priority_bitmap->line[1] - priority_bitmap->line[0];
  357.         return 0;
  358.     }
  359.     return -1;
  360. }
  361.  
  362. void tilemap_close( void ){
  363.     while( first_tilemap ){
  364.         struct tilemap *next = first_tilemap->next;
  365.         tilemap_dispose( first_tilemap );
  366.         first_tilemap = next;
  367.     }
  368.     osd_free_bitmap( priority_bitmap );
  369. }
  370.  
  371. /***********************************************************************************/
  372.  
  373. struct tilemap *tilemap_create(
  374.     void (*tile_get_info)( int memory_offset ),
  375.     UINT32 (*get_memory_offset)( UINT32 col, UINT32 row, UINT32 num_cols, UINT32 num_rows ),
  376.     int type,
  377.     int tile_width, int tile_height, /* in pixels */
  378.     int num_cols, int num_rows /* in tiles */
  379. ){
  380.     struct tilemap *tilemap = calloc( 1,sizeof( struct tilemap ) );
  381.     if( tilemap ){
  382.         int num_tiles = num_cols*num_rows;
  383.         tilemap->num_logical_cols = num_cols;
  384.         tilemap->num_logical_rows = num_rows;
  385.         if( Machine->orientation & ORIENTATION_SWAP_XY ){
  386.         logerror("swap!!\n" );
  387.             SWAP( tile_width, tile_height )
  388.             SWAP( num_cols,num_rows )
  389.         }
  390.         tilemap->num_cached_cols = num_cols;
  391.         tilemap->num_cached_rows = num_rows;
  392.         tilemap->num_tiles = num_tiles;
  393.         tilemap->cached_tile_width = tile_width;
  394.         tilemap->cached_tile_height = tile_height;
  395.         tilemap->cached_width = tile_width*num_cols;
  396.         tilemap->cached_height = tile_height*num_rows;
  397.         tilemap->tile_get_info = tile_get_info;
  398.         tilemap->get_memory_offset = get_memory_offset;
  399.         tilemap->orientation = Machine->orientation;
  400.         tilemap->enable = 1;
  401.         tilemap->type = type;
  402.         tilemap->scroll_rows = 1;
  403.         tilemap->scroll_cols = 1;
  404.         tilemap->transparent_pen = -1;
  405.         tilemap->cached_tile_info = calloc( num_tiles, sizeof(struct cached_tile_info) );
  406.         tilemap->priority = calloc( num_tiles,1 );
  407.         tilemap->visible = calloc( num_tiles,1 );
  408.         tilemap->dirty_vram = malloc( num_tiles );
  409.         tilemap->dirty_pixels = malloc( num_tiles );
  410.         tilemap->rowscroll = calloc(tilemap->cached_height,sizeof(int));
  411.         tilemap->colscroll = calloc(tilemap->cached_width,sizeof(int));
  412.         tilemap->priority_row = malloc( sizeof(UINT8 *)*num_rows );
  413.         tilemap->pixmap = create_tmpbitmap( tilemap->cached_width, tilemap->cached_height, Machine->scrbitmap->depth );
  414.         tilemap->foreground = mask_create( tilemap );
  415.         tilemap->background = (type & TILEMAP_SPLIT)?mask_create( tilemap ):NULL;
  416.         if( tilemap->cached_tile_info &&
  417.             tilemap->priority && tilemap->visible &&
  418.             tilemap->dirty_vram && tilemap->dirty_pixels &&
  419.             tilemap->rowscroll && tilemap->colscroll &&
  420.             tilemap->priority_row &&
  421.             tilemap->pixmap && tilemap->foreground &&
  422.             ((type&TILEMAP_SPLIT)==0 || tilemap->background) &&
  423.             (mappings_create( tilemap )==0)
  424.         ){
  425.             UINT32 row;
  426.             for( row=0; row<num_rows; row++ ){
  427.                 tilemap->priority_row[row] = tilemap->priority+num_cols*row;
  428.             }
  429.             install_draw_handlers( tilemap );
  430.             mappings_update( tilemap );
  431.             tilemap_set_clip( tilemap, &Machine->drv->visible_area );
  432.             memset( tilemap->dirty_vram, 1, num_tiles );
  433.             memset( tilemap->dirty_pixels, 1, num_tiles );
  434.             tilemap->pixmap_line_offset = tilemap->pixmap->line[1] - tilemap->pixmap->line[0];
  435.             tilemap->next = first_tilemap;
  436.             first_tilemap = tilemap;
  437.             return tilemap;
  438.         }
  439.         tilemap_dispose( tilemap );
  440.     }
  441.     return 0;
  442. }
  443.  
  444. void tilemap_dispose( struct tilemap *tilemap ){
  445.     if( tilemap==first_tilemap ){
  446.         first_tilemap = tilemap->next;
  447.     }
  448.     else {
  449.         struct tilemap *prev = first_tilemap;
  450.         while( prev->next != tilemap ) prev = prev->next;
  451.         prev->next =tilemap->next;
  452.     }
  453.  
  454.     free( tilemap->cached_tile_info );
  455.     free( tilemap->priority );
  456.     free( tilemap->visible );
  457.     free( tilemap->dirty_vram );
  458.     free( tilemap->dirty_pixels );
  459.     free( tilemap->rowscroll );
  460.     free( tilemap->colscroll );
  461.     free( tilemap->priority_row );
  462.     osd_free_bitmap( tilemap->pixmap );
  463.     mask_dispose( tilemap->foreground );
  464.     mask_dispose( tilemap->background );
  465.     mappings_dispose( tilemap );
  466.     free( tilemap );
  467. }
  468.  
  469. /***********************************************************************************/
  470.  
  471. static void unregister_pens( struct cached_tile_info *cached_tile_info, int num_pens ){
  472.     const UINT16 *pal_data = cached_tile_info->pal_data;
  473.     if( pal_data ){
  474.         UINT32 pen_usage = cached_tile_info->pen_usage;
  475.         if( pen_usage ){
  476.             palette_decrease_usage_count(
  477.                 pal_data-Machine->remapped_colortable,
  478.                 pen_usage,
  479.                 PALETTE_COLOR_VISIBLE|PALETTE_COLOR_CACHED );
  480.         }
  481.         else {
  482.             palette_decrease_usage_countx(
  483.                 pal_data-Machine->remapped_colortable,
  484.                 num_pens,
  485.                 cached_tile_info->pen_data,
  486.                 PALETTE_COLOR_VISIBLE|PALETTE_COLOR_CACHED );
  487.         }
  488.         cached_tile_info->pal_data = NULL;
  489.     }
  490. }
  491.  
  492. static void register_pens( struct cached_tile_info *cached_tile_info, int num_pens ){
  493.     UINT32 pen_usage = cached_tile_info->pen_usage;
  494.     if( pen_usage ){
  495.         palette_increase_usage_count(
  496.             cached_tile_info->pal_data-Machine->remapped_colortable,
  497.             pen_usage,
  498.             PALETTE_COLOR_VISIBLE|PALETTE_COLOR_CACHED );
  499.     }
  500.     else {
  501.         palette_increase_usage_countx(
  502.             cached_tile_info->pal_data-Machine->remapped_colortable,
  503.             num_pens,
  504.             cached_tile_info->pen_data,
  505.             PALETTE_COLOR_VISIBLE|PALETTE_COLOR_CACHED );
  506.     }
  507. }
  508.  
  509. /***********************************************************************************/
  510.  
  511. void tilemap_set_enable( struct tilemap *tilemap, int enable ){
  512.     tilemap->enable = enable;
  513. }
  514.  
  515. void tilemap_set_flip( struct tilemap *tilemap, int attributes ){
  516.     if( tilemap==ALL_TILEMAPS ){
  517.         tilemap = first_tilemap;
  518.         while( tilemap ){
  519.             tilemap_set_flip( tilemap, attributes );
  520.             tilemap = tilemap->next;
  521.         }
  522.     }
  523.     else if( tilemap->attributes!=attributes ){
  524.         tilemap->attributes = attributes;
  525.         tilemap->orientation = Machine->orientation;
  526.         if( attributes&TILEMAP_FLIPY ){
  527.             tilemap->orientation ^= ORIENTATION_FLIP_Y;
  528.             tilemap->scrolly_delta = tilemap->dy_if_flipped;
  529.         }
  530.         else {
  531.             tilemap->scrolly_delta = tilemap->dy;
  532.         }
  533.         if( attributes&TILEMAP_FLIPX ){
  534.             tilemap->orientation ^= ORIENTATION_FLIP_X;
  535.             tilemap->scrollx_delta = tilemap->dx_if_flipped;
  536.         }
  537.         else {
  538.             tilemap->scrollx_delta = tilemap->dx;
  539.         }
  540.  
  541.         mappings_update( tilemap );
  542.         tilemap_mark_all_tiles_dirty( tilemap );
  543.     }
  544. }
  545.  
  546. void tilemap_set_clip( struct tilemap *tilemap, const struct rectangle *clip ){
  547.     int left,top,right,bottom;
  548.     if( clip ){
  549.         left = clip->min_x;
  550.         top = clip->min_y;
  551.         right = clip->max_x+1;
  552.         bottom = clip->max_y+1;
  553.         if( tilemap->orientation & ORIENTATION_SWAP_XY ){
  554.             SWAP(left,top)
  555.             SWAP(right,bottom)
  556.         }
  557.         if( tilemap->orientation & ORIENTATION_FLIP_X ){
  558.             SWAP(left,right)
  559.             left = screen_width-left;
  560.             right = screen_width-right;
  561.         }
  562.         if( tilemap->orientation & ORIENTATION_FLIP_Y ){
  563.             SWAP(top,bottom)
  564.             top = screen_height-top;
  565.             bottom = screen_height-bottom;
  566.         }
  567.     }
  568.     else {
  569.         left = 0;
  570.         top = 0;
  571.         right = tilemap->cached_width;
  572.         bottom = tilemap->cached_height;
  573.     }
  574.     tilemap->clip_left = left;
  575.     tilemap->clip_right = right;
  576.     tilemap->clip_top = top;
  577.     tilemap->clip_bottom = bottom;
  578. //    logerror("clip: %d,%d,%d,%d\n", left,top,right,bottom );
  579. }
  580.  
  581. /***********************************************************************************/
  582.  
  583. void tilemap_set_scroll_cols( struct tilemap *tilemap, int n ){
  584.     if( tilemap->orientation & ORIENTATION_SWAP_XY ){
  585.         if (tilemap->scroll_rows != n){
  586.             tilemap->scroll_rows = n;
  587.         }
  588.     }
  589.     else {
  590.         if (tilemap->scroll_cols != n){
  591.             tilemap->scroll_cols = n;
  592.         }
  593.     }
  594. }
  595.  
  596. void tilemap_set_scroll_rows( struct tilemap *tilemap, int n ){
  597.     if( tilemap->orientation & ORIENTATION_SWAP_XY ){
  598.         if (tilemap->scroll_cols != n){
  599.             tilemap->scroll_cols = n;
  600.         }
  601.     }
  602.     else {
  603.         if (tilemap->scroll_rows != n){
  604.             tilemap->scroll_rows = n;
  605.         }
  606.     }
  607. }
  608.  
  609. /***********************************************************************************/
  610.  
  611. void tilemap_mark_tile_dirty( struct tilemap *tilemap, int memory_offset ){
  612.     if( memory_offset<tilemap->max_memory_offset ){
  613.         int cached_index = tilemap->memory_offset_to_cached_index[memory_offset];
  614.         if( cached_index>=0 ){
  615.             tilemap->dirty_vram[cached_index] = 1;
  616.         }
  617.     }
  618. }
  619.  
  620. void tilemap_mark_all_tiles_dirty( struct tilemap *tilemap ){
  621.     if( tilemap==ALL_TILEMAPS ){
  622.         tilemap = first_tilemap;
  623.         while( tilemap ){
  624.             tilemap_mark_all_tiles_dirty( tilemap );
  625.             tilemap = tilemap->next;
  626.         }
  627.     }
  628.     else {
  629.         memset( tilemap->dirty_vram, 1, tilemap->num_tiles );
  630.     }
  631. }
  632.  
  633. void tilemap_mark_all_pixels_dirty( struct tilemap *tilemap ){
  634.     if( tilemap==ALL_TILEMAPS ){
  635.         tilemap = first_tilemap;
  636.         while( tilemap ){
  637.             tilemap_mark_all_pixels_dirty( tilemap );
  638.             tilemap = tilemap->next;
  639.         }
  640.     }
  641.     else {
  642.         /* invalidate all offscreen tiles */
  643.         UINT32 cached_tile_index;
  644.         UINT32 num_pens = tilemap->cached_tile_width*tilemap->cached_tile_height;
  645.         for( cached_tile_index=0; cached_tile_index<tilemap->num_tiles; cached_tile_index++ ){
  646.             if( !tilemap->visible[cached_tile_index] ){
  647.                 unregister_pens( &tilemap->cached_tile_info[cached_tile_index], num_pens );
  648.                 tilemap->dirty_vram[cached_tile_index] = 1;
  649.             }
  650.         }
  651.         memset( tilemap->dirty_pixels, 1, tilemap->num_tiles );
  652.     }
  653. }
  654.  
  655. /***********************************************************************************/
  656.  
  657. static void draw_tile(
  658.         struct tilemap *tilemap,
  659.         UINT32 cached_index,
  660.         UINT32 col, UINT32 row
  661. ){
  662.     struct osd_bitmap *pixmap = tilemap->pixmap;
  663.     UINT32 tile_width = tilemap->cached_tile_width;
  664.     UINT32 tile_height = tilemap->cached_tile_height;
  665.     struct cached_tile_info *cached_tile_info = &tilemap->cached_tile_info[cached_index];
  666.     const UINT8 *pendata = cached_tile_info->pen_data;
  667.     const UINT16 *paldata = cached_tile_info->pal_data;
  668.  
  669.     UINT32 flags = cached_tile_info->flags;
  670.     int x, sx = tile_width*col;
  671.     int sy,y1,y2,dy;
  672.  
  673.     if( Machine->scrbitmap->depth==16 ){
  674.         if( flags&TILE_FLIPY ){
  675.             y1 = tile_height*row+tile_height-1;
  676.             y2 = y1-tile_height;
  677.              dy = -1;
  678.          }
  679.          else {
  680.             y1 = tile_height*row;
  681.             y2 = y1+tile_height;
  682.              dy = 1;
  683.          }
  684.  
  685.         if( flags&TILE_FLIPX ){
  686.             tile_width--;
  687.             for( sy=y1; sy!=y2; sy+=dy ){
  688.                 UINT16 *dest  = sx + (UINT16 *)pixmap->line[sy];
  689.                 for( x=tile_width; x>=0; x-- ) dest[x] = paldata[*pendata++];
  690.             }
  691.         }
  692.         else {
  693.             for( sy=y1; sy!=y2; sy+=dy ){
  694.                 UINT16 *dest  = sx + (UINT16 *)pixmap->line[sy];
  695.                 for( x=0; x<tile_width; x++ ) dest[x] = paldata[*pendata++];
  696.             }
  697.         }
  698.     }
  699.     else {
  700.         if( flags&TILE_FLIPY ){
  701.             y1 = tile_height*row+tile_height-1;
  702.             y2 = y1-tile_height;
  703.              dy = -1;
  704.          }
  705.          else {
  706.             y1 = tile_height*row;
  707.             y2 = y1+tile_height;
  708.              dy = 1;
  709.          }
  710.  
  711.         if( flags&TILE_FLIPX ){
  712.             tile_width--;
  713.             for( sy=y1; sy!=y2; sy+=dy ){
  714.                 UINT8 *dest  = sx + (UINT8 *)pixmap->line[sy];
  715.                 for( x=tile_width; x>=0; x-- ) dest[x] = paldata[*pendata++];
  716.             }
  717.         }
  718.         else {
  719.             for( sy=y1; sy!=y2; sy+=dy ){
  720.                 UINT8 *dest  = sx + (UINT8 *)pixmap->line[sy];
  721.                 for( x=0; x<tile_width; x++ ) dest[x] = paldata[*pendata++];
  722.             }
  723.         }
  724.     }
  725. }
  726.  
  727. void tilemap_render( struct tilemap *tilemap ){
  728.     if( tilemap==ALL_TILEMAPS ){
  729.         tilemap = first_tilemap;
  730.         while( tilemap ){
  731.             tilemap_render( tilemap );
  732.             tilemap = tilemap->next;
  733.         }
  734.     }
  735.     else if( tilemap->enable ){
  736.         UINT8 *dirty_pixels = tilemap->dirty_pixels;
  737.         const UINT8 *visible = tilemap->visible;
  738.         UINT32 cached_index = 0;
  739.         UINT32 row,col;
  740.  
  741.         /* walk over cached rows/cols (better to walk screen coords) */
  742.         for( row=0; row<tilemap->num_cached_rows; row++ ){
  743.             for( col=0; col<tilemap->num_cached_cols; col++ ){
  744.                 if( visible[cached_index] && dirty_pixels[cached_index] ){
  745.                     draw_tile( tilemap, cached_index, col, row );
  746.                     dirty_pixels[cached_index] = 0;
  747.                 }
  748.                 cached_index++;
  749.             } /* next col */
  750.         } /* next row */
  751.     }
  752. }
  753.  
  754. /***********************************************************************************/
  755.  
  756. static int draw_bitmask(
  757.         struct osd_bitmap *mask,
  758.         UINT32 col, UINT32 row,
  759.         UINT32 tile_width, UINT32 tile_height,
  760.         const UINT8 *maskdata,
  761.         UINT32 flags )
  762. {
  763.     int is_opaque = 1, is_transparent = 1;
  764.     int x,sx = tile_width*col;
  765.     int sy,y1,y2,dy;
  766.  
  767.     if( maskdata==TILEMAP_BITMASK_TRANSPARENT ) return TILE_TRANSPARENT;
  768.     if( maskdata==TILEMAP_BITMASK_OPAQUE) return TILE_OPAQUE;
  769.  
  770.     if( flags&TILE_FLIPY ){
  771.         y1 = tile_height*row+tile_height-1;
  772.         y2 = y1-tile_height;
  773.          dy = -1;
  774.      }
  775.      else {
  776.         y1 = tile_height*row;
  777.         y2 = y1+tile_height;
  778.          dy = 1;
  779.      }
  780.  
  781.     if( flags&TILE_FLIPX ){
  782.         tile_width--;
  783.         for( sy=y1; sy!=y2; sy+=dy ){
  784.             UINT8 *mask_dest  = mask->line[sy]+sx/8;
  785.             for( x=tile_width/8; x>=0; x-- ){
  786.                 UINT8 data = flip_bit_table[*maskdata++];
  787.                 if( data!=0x00 ) is_transparent = 0;
  788.                 if( data!=0xff ) is_opaque = 0;
  789.                 mask_dest[x] = data;
  790.             }
  791.         }
  792.     }
  793.     else {
  794.         for( sy=y1; sy!=y2; sy+=dy ){
  795.             UINT8 *mask_dest  = mask->line[sy]+sx/8;
  796.             for( x=0; x<tile_width/8; x++ ){
  797.                 UINT8 data = *maskdata++;
  798.                 if( data!=0x00 ) is_transparent = 0;
  799.                 if( data!=0xff ) is_opaque = 0;
  800.                 mask_dest[x] = data;
  801.             }
  802.         }
  803.     }
  804.  
  805.     if( is_transparent ) return TILE_TRANSPARENT;
  806.     if( is_opaque ) return TILE_OPAQUE;
  807.     return TILE_MASKED;
  808. }
  809.  
  810. static int draw_color_mask(
  811.     struct osd_bitmap *mask,
  812.     UINT32 col, UINT32 row,
  813.     UINT32 tile_width, UINT32 tile_height,
  814.     const UINT8 *pendata,
  815.     const UINT16 *clut,
  816.     int transparent_color,
  817.     UINT32 flags )
  818. {
  819.     int is_opaque = 1, is_transparent = 1;
  820.  
  821.     int x,bit,sx = tile_width*col;
  822.     int sy,y1,y2,dy;
  823.  
  824.     if( flags&TILE_FLIPY ){
  825.         y1 = tile_height*row+tile_height-1;
  826.         y2 = y1-tile_height;
  827.          dy = -1;
  828.      }
  829.      else {
  830.         y1 = tile_height*row;
  831.         y2 = y1+tile_height;
  832.          dy = 1;
  833.      }
  834.  
  835.     if( flags&TILE_FLIPX ){
  836.         tile_width--;
  837.         for( sy=y1; sy!=y2; sy+=dy ){
  838.             UINT8 *mask_dest  = mask->line[sy]+sx/8;
  839.             for( x=tile_width/8; x>=0; x-- ){
  840.                 UINT32 data = 0;
  841.                 for( bit=0; bit<8; bit++ ){
  842.                     UINT32 pen = *pendata++;
  843.                     data = data>>1;
  844.                     if( clut[pen]!=transparent_color ) data |=0x80;
  845.                 }
  846.                 if( data!=0x00 ) is_transparent = 0;
  847.                 if( data!=0xff ) is_opaque = 0;
  848.                 mask_dest[x] = data;
  849.             }
  850.         }
  851.     }
  852.     else {
  853.         for( sy=y1; sy!=y2; sy+=dy ){
  854.             UINT8 *mask_dest  = mask->line[sy]+sx/8;
  855.             for( x=0; x<tile_width/8; x++ ){
  856.                 UINT32 data = 0;
  857.                 for( bit=0; bit<8; bit++ ){
  858.                     UINT32 pen = *pendata++;
  859.                     data = data<<1;
  860.                     if( clut[pen]!=transparent_color ) data |=0x01;
  861.                 }
  862.                 if( data!=0x00 ) is_transparent = 0;
  863.                 if( data!=0xff ) is_opaque = 0;
  864.                 mask_dest[x] = data;
  865.             }
  866.         }
  867.     }
  868.     if( is_transparent ) return TILE_TRANSPARENT;
  869.     if( is_opaque ) return TILE_OPAQUE;
  870.     return TILE_MASKED;
  871. }
  872.  
  873. static int draw_pen_mask(
  874.     struct osd_bitmap *mask,
  875.     UINT32 col, UINT32 row,
  876.     UINT32 tile_width, UINT32 tile_height,
  877.     const UINT8 *pendata,
  878.     int transparent_pen,
  879.     UINT32 flags )
  880. {
  881.     int is_opaque = 1, is_transparent = 1;
  882.  
  883.     int x,bit,sx = tile_width*col;
  884.     int sy,y1,y2,dy;
  885.  
  886.     if( flags&TILE_FLIPY ){
  887.         y1 = tile_height*row+tile_height-1;
  888.         y2 = y1-tile_height;
  889.          dy = -1;
  890.      }
  891.      else {
  892.         y1 = tile_height*row;
  893.         y2 = y1+tile_height;
  894.          dy = 1;
  895.      }
  896.  
  897.     if( flags&TILE_FLIPX ){
  898.         tile_width--;
  899.         for( sy=y1; sy!=y2; sy+=dy ){
  900.             UINT8 *mask_dest  = mask->line[sy]+sx/8;
  901.             for( x=tile_width/8; x>=0; x-- ){
  902.                 UINT32 data = 0;
  903.                 for( bit=0; bit<8; bit++ ){
  904.                     UINT32 pen = *pendata++;
  905.                     data = data>>1;
  906.                     if( pen!=transparent_pen ) data |=0x80;
  907.                 }
  908.                 if( data!=0x00 ) is_transparent = 0;
  909.                 if( data!=0xff ) is_opaque = 0;
  910.                 mask_dest[x] = data;
  911.             }
  912.         }
  913.     }
  914.     else {
  915.         for( sy=y1; sy!=y2; sy+=dy ){
  916.             UINT8 *mask_dest  = mask->line[sy]+sx/8;
  917.             for( x=0; x<tile_width/8; x++ ){
  918.                 UINT32 data = 0;
  919.                 for( bit=0; bit<8; bit++ ){
  920.                     UINT32 pen = *pendata++;
  921.                     data = data<<1;
  922.                     if( pen!=transparent_pen ) data |=0x01;
  923.                 }
  924.                 if( data!=0x00 ) is_transparent = 0;
  925.                 if( data!=0xff ) is_opaque = 0;
  926.                 mask_dest[x] = data;
  927.             }
  928.         }
  929.     }
  930.     if( is_transparent ) return TILE_TRANSPARENT;
  931.     if( is_opaque ) return TILE_OPAQUE;
  932.     return TILE_MASKED;
  933. }
  934.  
  935. static void draw_mask(
  936.     struct osd_bitmap *mask,
  937.     UINT32 col, UINT32 row,
  938.     UINT32 tile_width, UINT32 tile_height,
  939.     const UINT8 *pendata,
  940.     UINT32 transmask,
  941.     UINT32 flags )
  942. {
  943.     int x,bit,sx = tile_width*col;
  944.     int sy,y1,y2,dy;
  945.  
  946.     if( flags&TILE_FLIPY ){
  947.         y1 = tile_height*row+tile_height-1;
  948.         y2 = y1-tile_height;
  949.          dy = -1;
  950.      }
  951.      else {
  952.         y1 = tile_height*row;
  953.         y2 = y1+tile_height;
  954.          dy = 1;
  955.      }
  956.  
  957.     if( flags&TILE_FLIPX ){
  958.         tile_width--;
  959.         for( sy=y1; sy!=y2; sy+=dy ){
  960.             UINT8 *mask_dest  = mask->line[sy]+sx/8;
  961.             for( x=tile_width/8; x>=0; x-- ){
  962.                 UINT32 data = 0;
  963.                 for( bit=0; bit<8; bit++ ){
  964.                     UINT32 pen = *pendata++;
  965.                     data = data>>1;
  966.                     if( !((1<<pen)&transmask) ) data |= 0x80;
  967.                 }
  968.                 mask_dest[x] = data;
  969.             }
  970.         }
  971.     }
  972.     else {
  973.         for( sy=y1; sy!=y2; sy+=dy ){
  974.             UINT8 *mask_dest  = mask->line[sy]+sx/8;
  975.             for( x=0; x<tile_width/8; x++ ){
  976.                 UINT32 data = 0;
  977.                 for( bit=0; bit<8; bit++ ){
  978.                     UINT32 pen = *pendata++;
  979.                     data = (data<<1);
  980.                     if( !((1<<pen)&transmask) ) data |= 0x01;
  981.                 }
  982.                 mask_dest[x] = data;
  983.             }
  984.         }
  985.     }
  986. }
  987.  
  988. static void render_mask( struct tilemap *tilemap, UINT32 cached_index ){
  989.     const struct cached_tile_info *cached_tile_info = &tilemap->cached_tile_info[cached_index];
  990.     UINT32 col = cached_index%tilemap->num_cached_cols;
  991.     UINT32 row = cached_index/tilemap->num_cached_cols;
  992.     UINT32 type = tilemap->type;
  993.  
  994.     UINT32 transparent_pen = tilemap->transparent_pen;
  995.     UINT32 *transmask = tilemap->transmask;
  996.     UINT32 tile_width = tilemap->cached_tile_width;
  997.     UINT32 tile_height = tilemap->cached_tile_height;
  998.  
  999.     UINT32 pen_usage = cached_tile_info->pen_usage;
  1000.     const UINT8 *pen_data = cached_tile_info->pen_data;
  1001.     UINT32 flags = cached_tile_info->flags;
  1002.  
  1003.     if( type & TILEMAP_BITMASK ){
  1004.         tilemap->foreground->data_row[row][col] =
  1005.             draw_bitmask( tilemap->foreground->bitmask,col, row,
  1006.                 tile_width, tile_height,tile_info.mask_data, flags );
  1007.     }
  1008.     else if( type & TILEMAP_SPLIT ){
  1009.         UINT32 pen_mask = (transparent_pen<0)?0:(1<<transparent_pen);
  1010.         if( flags&TILE_IGNORE_TRANSPARENCY ){
  1011.             tilemap->foreground->data_row[row][col] = TILE_OPAQUE;
  1012.             tilemap->background->data_row[row][col] = TILE_OPAQUE;
  1013.         }
  1014.         else if( pen_mask == pen_usage ){ /* totally transparent */
  1015.             tilemap->foreground->data_row[row][col] = TILE_TRANSPARENT;
  1016.             tilemap->background->data_row[row][col] = TILE_TRANSPARENT;
  1017.         }
  1018.         else {
  1019.             UINT32 fg_transmask = transmask[(flags>>2)&3];
  1020.             UINT32 bg_transmask = (~fg_transmask)|pen_mask;
  1021.             if( (pen_usage & fg_transmask)==0 ){ /* foreground totally opaque */
  1022.                 tilemap->foreground->data_row[row][col] = TILE_OPAQUE;
  1023.                 tilemap->background->data_row[row][col] = TILE_TRANSPARENT;
  1024.             }
  1025.             else if( (pen_usage & bg_transmask)==0 ){ /* background totally opaque */
  1026.                 tilemap->foreground->data_row[row][col] = TILE_TRANSPARENT;
  1027.                 tilemap->background->data_row[row][col] = TILE_OPAQUE;
  1028.             }
  1029.             else if( (pen_usage & ~bg_transmask)==0 ){ /* background transparent */
  1030.                 draw_mask( tilemap->foreground->bitmask,
  1031.                     col, row, tile_width, tile_height,
  1032.                     pen_data, fg_transmask, flags );
  1033.                 tilemap->foreground->data_row[row][col] = TILE_MASKED;
  1034.                 tilemap->background->data_row[row][col] = TILE_TRANSPARENT;
  1035.             }
  1036.             else if( (pen_usage & ~fg_transmask)==0 ){ /* foreground transparent */
  1037.                 draw_mask( tilemap->background->bitmask,
  1038.                     col, row, tile_width, tile_height,
  1039.                     pen_data, bg_transmask, flags );
  1040.                 tilemap->foreground->data_row[row][col] = TILE_TRANSPARENT;
  1041.                 tilemap->background->data_row[row][col] = TILE_MASKED;
  1042.             }
  1043.             else { /* split tile - opacity in both foreground and background */
  1044.                 draw_mask( tilemap->foreground->bitmask,
  1045.                     col, row, tile_width, tile_height,
  1046.                     pen_data, fg_transmask, flags );
  1047.                 draw_mask( tilemap->background->bitmask,
  1048.                     col, row, tile_width, tile_height,
  1049.                     pen_data, bg_transmask, flags );
  1050.                 tilemap->foreground->data_row[row][col] = TILE_MASKED;
  1051.                 tilemap->background->data_row[row][col] = TILE_MASKED;
  1052.             }
  1053.         }
  1054.     }
  1055.     else if( type==TILEMAP_TRANSPARENT ){
  1056.         if( pen_usage ){
  1057.             UINT32 fg_transmask = 1 << transparent_pen;
  1058.              if( flags&TILE_IGNORE_TRANSPARENCY ) fg_transmask = 0;
  1059.             if( pen_usage == fg_transmask ){
  1060.                 tilemap->foreground->data_row[row][col] = TILE_TRANSPARENT;
  1061.             }
  1062.             else if( pen_usage & fg_transmask ){
  1063.                 draw_mask( tilemap->foreground->bitmask,
  1064.                     col, row, tile_width, tile_height,
  1065.                     pen_data, fg_transmask, flags );
  1066.                 tilemap->foreground->data_row[row][col] = TILE_MASKED;
  1067.             }
  1068.             else {
  1069.                 tilemap->foreground->data_row[row][col] = TILE_OPAQUE;
  1070.             }
  1071.         }
  1072.         else {
  1073.             tilemap->foreground->data_row[row][col] =
  1074.                 draw_pen_mask(
  1075.                     tilemap->foreground->bitmask,
  1076.                     col, row, tile_width, tile_height,
  1077.                     pen_data,
  1078.                     transparent_pen,
  1079.                     flags
  1080.                 );
  1081.         }
  1082.     }
  1083.     else if( type==TILEMAP_TRANSPARENT_COLOR ){
  1084.         tilemap->foreground->data_row[row][col] =
  1085.             draw_color_mask(
  1086.                 tilemap->foreground->bitmask,
  1087.                 col, row, tile_width, tile_height,
  1088.                 pen_data,
  1089.                 Machine->game_colortable +
  1090.                     (cached_tile_info->pal_data - Machine->remapped_colortable),
  1091.                 transparent_pen,
  1092.                 flags
  1093.             );
  1094.     }
  1095.     else {
  1096.         tilemap->foreground->data_row[row][col] = TILE_OPAQUE;
  1097.     }
  1098. }
  1099.  
  1100. static void update_tile_info( struct tilemap *tilemap ){
  1101.     int *logical_flip_to_cached_flip = tilemap->logical_flip_to_cached_flip;
  1102.     UINT32 num_pens = tilemap->cached_tile_width*tilemap->cached_tile_height;
  1103.     UINT32 num_tiles = tilemap->num_tiles;
  1104.     UINT32 cached_index;
  1105.     UINT8 *visible = tilemap->visible;
  1106.     UINT8 *dirty_vram = tilemap->dirty_vram;
  1107.     UINT8 *dirty_pixels = tilemap->dirty_pixels;
  1108.     tile_info.flags = 0;
  1109.     tile_info.priority = 0;
  1110.     for( cached_index=0; cached_index<num_tiles; cached_index++ ){
  1111.         if( visible[cached_index] && dirty_vram[cached_index] ){
  1112.             struct cached_tile_info *cached_tile_info = &tilemap->cached_tile_info[cached_index];
  1113.             UINT32 memory_offset = tilemap->cached_index_to_memory_offset[cached_index];
  1114.             unregister_pens( cached_tile_info, num_pens );
  1115.             tilemap->tile_get_info( memory_offset );
  1116.             {
  1117.                 UINT32 flags = tile_info.flags;
  1118.                 cached_tile_info->flags = (flags&0xfc)|logical_flip_to_cached_flip[flags&0x3];
  1119.             }
  1120.             cached_tile_info->pen_usage = tile_info.pen_usage;
  1121.             cached_tile_info->pen_data = tile_info.pen_data;
  1122.             cached_tile_info->pal_data = tile_info.pal_data;
  1123.             tilemap->priority[cached_index] = tile_info.priority;
  1124.             register_pens( cached_tile_info, num_pens );
  1125.             dirty_pixels[cached_index] = 1;
  1126.             dirty_vram[cached_index] = 0;
  1127.             render_mask( tilemap, cached_index );
  1128.         }
  1129.     }
  1130. }
  1131.  
  1132. static void update_visible( struct tilemap *tilemap ){
  1133.     // temporary hack
  1134.     memset( tilemap->visible, 1, tilemap->num_tiles );
  1135.  
  1136. #if 0
  1137.     int yscroll = scrolly[0];
  1138.     int row0, y0;
  1139.  
  1140.     int xscroll = scrollx[0];
  1141.     int col0, x0;
  1142.  
  1143.     if( yscroll>=0 ){
  1144.         row0 = yscroll/tile_height;
  1145.         y0 = -(yscroll%tile_height);
  1146.     }
  1147.     else {
  1148.         yscroll = tile_height-1-yscroll;
  1149.         row0 = num_rows - yscroll/tile_height;
  1150.         y0 = (yscroll+1)%tile_height;
  1151.         if( y0 ) y0 = y0-tile_height;
  1152.     }
  1153.  
  1154.     if( xscroll>=0 ){
  1155.         col0 = xscroll/tile_width;
  1156.         x0 = -(xscroll%tile_width);
  1157.     }
  1158.     else {
  1159.         xscroll = tile_width-1-xscroll;
  1160.         col0 = num_cols - xscroll/tile_width;
  1161.         x0 = (xscroll+1)%tile_width;
  1162.         if( x0 ) x0 = x0-tile_width;
  1163.     }
  1164.  
  1165.     {
  1166.         int ypos = y0;
  1167.         int row = row0;
  1168.         while( ypos<screen_height ){
  1169.             int xpos = x0;
  1170.             int col = col0;
  1171.             while( xpos<screen_width ){
  1172.                 process_visible_tile( col, row );
  1173.                 col++;
  1174.                 if( col>=num_cols ) col = 0;
  1175.                 xpos += tile_width;
  1176.             }
  1177.             row++;
  1178.             if( row>=num_rows ) row = 0;
  1179.             ypos += tile_height;
  1180.         }
  1181.     }
  1182. #endif
  1183. }
  1184.  
  1185. void tilemap_update( struct tilemap *tilemap ){
  1186.     if( tilemap==ALL_TILEMAPS ){
  1187.         tilemap = first_tilemap;
  1188.         while( tilemap ){
  1189.             tilemap_update( tilemap );
  1190.             tilemap = tilemap->next;
  1191.         }
  1192.     }
  1193.     else if( tilemap->enable ){
  1194.         update_visible( tilemap );
  1195.         update_tile_info( tilemap );
  1196.     }
  1197. }
  1198.  
  1199. /***********************************************************************************/
  1200.  
  1201. void tilemap_set_scrolldx( struct tilemap *tilemap, int dx, int dx_if_flipped ){
  1202.     tilemap->dx = dx;
  1203.     tilemap->dx_if_flipped = dx_if_flipped;
  1204.     tilemap->scrollx_delta = ( tilemap->attributes & TILEMAP_FLIPX )?dx_if_flipped:dx;
  1205. }
  1206.  
  1207. void tilemap_set_scrolldy( struct tilemap *tilemap, int dy, int dy_if_flipped ){
  1208.     tilemap->dy = dy;
  1209.     tilemap->dy_if_flipped = dy_if_flipped;
  1210.     tilemap->scrolly_delta = ( tilemap->attributes & TILEMAP_FLIPY )?dy_if_flipped:dy;
  1211. }
  1212.  
  1213. void tilemap_set_scrollx( struct tilemap *tilemap, int which, int value ){
  1214.     value = tilemap->scrollx_delta-value;
  1215.  
  1216.     if( tilemap->orientation & ORIENTATION_SWAP_XY ){
  1217.         if( tilemap->orientation & ORIENTATION_FLIP_X ) which = tilemap->scroll_cols-1 - which;
  1218.         if( tilemap->orientation & ORIENTATION_FLIP_Y ) value = screen_height-tilemap->cached_height-value;
  1219.         if( tilemap->colscroll[which]!=value ){
  1220.             tilemap->colscroll[which] = value;
  1221.         }
  1222.     }
  1223.     else {
  1224.         if( tilemap->orientation & ORIENTATION_FLIP_Y ) which = tilemap->scroll_rows-1 - which;
  1225.         if( tilemap->orientation & ORIENTATION_FLIP_X ) value = screen_width-tilemap->cached_width-value;
  1226.         if( tilemap->rowscroll[which]!=value ){
  1227.             tilemap->rowscroll[which] = value;
  1228.         }
  1229.     }
  1230. }
  1231. void tilemap_set_scrolly( struct tilemap *tilemap, int which, int value ){
  1232.     value = tilemap->scrolly_delta - value;
  1233.  
  1234.     if( tilemap->orientation & ORIENTATION_SWAP_XY ){
  1235.         if( tilemap->orientation & ORIENTATION_FLIP_Y ) which = tilemap->scroll_rows-1 - which;
  1236.         if( tilemap->orientation & ORIENTATION_FLIP_X ) value = screen_width-tilemap->cached_width-value;
  1237.         if( tilemap->rowscroll[which]!=value ){
  1238.             tilemap->rowscroll[which] = value;
  1239.         }
  1240.     }
  1241.     else {
  1242.         if( tilemap->orientation & ORIENTATION_FLIP_X ) which = tilemap->scroll_cols-1 - which;
  1243.         if( tilemap->orientation & ORIENTATION_FLIP_Y ) value = screen_height-tilemap->cached_height-value;
  1244.         if( tilemap->colscroll[which]!=value ){
  1245.             tilemap->colscroll[which] = value;
  1246.         }
  1247.     }
  1248. }
  1249. /***********************************************************************************/
  1250.  
  1251. void tilemap_draw( struct osd_bitmap *dest, struct tilemap *tilemap, UINT32 priority ){
  1252.     int xpos,ypos;
  1253.  
  1254.     if( tilemap->enable ){
  1255.         void (*draw)( int, int );
  1256.  
  1257.         int rows = tilemap->scroll_rows;
  1258.         const int *rowscroll = tilemap->rowscroll;
  1259.         int cols = tilemap->scroll_cols;
  1260.         const int *colscroll = tilemap->colscroll;
  1261.  
  1262.         int left = tilemap->clip_left;
  1263.         int right = tilemap->clip_right;
  1264.         int top = tilemap->clip_top;
  1265.         int bottom = tilemap->clip_bottom;
  1266.  
  1267.         int tile_height = tilemap->cached_tile_height;
  1268.  
  1269.         blit.screen = dest;
  1270.         blit.dest_line_offset = dest->line[1] - dest->line[0];
  1271.  
  1272.         blit.pixmap = tilemap->pixmap;
  1273.         blit.source_line_offset = tilemap->pixmap_line_offset;
  1274.  
  1275.         if( tilemap->type==TILEMAP_OPAQUE || (priority&TILEMAP_IGNORE_TRANSPARENCY) ){
  1276.             draw = tilemap->draw_opaque;
  1277.         }
  1278.         else {
  1279.             draw = tilemap->draw;
  1280.             if( priority&TILEMAP_BACK ){
  1281.                 blit.bitmask = tilemap->background->bitmask;
  1282.                 blit.mask_line_offset = tilemap->background->line_offset;
  1283.                 blit.mask_data_row = tilemap->background->data_row;
  1284.             }
  1285.             else {
  1286.                 blit.bitmask = tilemap->foreground->bitmask;
  1287.                 blit.mask_line_offset = tilemap->foreground->line_offset;
  1288.                 blit.mask_data_row = tilemap->foreground->data_row;
  1289.             }
  1290.  
  1291.             blit.mask_row_offset = tile_height*blit.mask_line_offset;
  1292.         }
  1293.  
  1294.         if( dest->depth==16 ){
  1295.             blit.dest_line_offset /= 2;
  1296.             blit.source_line_offset /= 2;
  1297.         }
  1298.  
  1299.         blit.source_row_offset = tile_height*blit.source_line_offset;
  1300.         blit.dest_row_offset = tile_height*blit.dest_line_offset;
  1301.  
  1302.         blit.priority_data_row = tilemap->priority_row;
  1303.         blit.source_width = tilemap->cached_width;
  1304.         blit.source_height = tilemap->cached_height;
  1305.         blit.tile_priority = priority&0xf;
  1306.         blit.tilemap_priority_code = priority>>16;
  1307.  
  1308.         if( rows == 1 && cols == 1 ){ /* XY scrolling playfield */
  1309.             int scrollx = rowscroll[0];
  1310.             int scrolly = colscroll[0];
  1311.  
  1312.             if( scrollx < 0 ){
  1313.                 scrollx = blit.source_width - (-scrollx) % blit.source_width;
  1314.             }
  1315.             else {
  1316.                 scrollx = scrollx % blit.source_width;
  1317.             }
  1318.  
  1319.             if( scrolly < 0 ){
  1320.                 scrolly = blit.source_height - (-scrolly) % blit.source_height;
  1321.             }
  1322.             else {
  1323.                 scrolly = scrolly % blit.source_height;
  1324.             }
  1325.  
  1326.              blit.clip_left = left;
  1327.              blit.clip_top = top;
  1328.              blit.clip_right = right;
  1329.              blit.clip_bottom = bottom;
  1330.  
  1331.             for(
  1332.                 ypos = scrolly - blit.source_height;
  1333.                 ypos < blit.clip_bottom;
  1334.                 ypos += blit.source_height
  1335.             ){
  1336.                 for(
  1337.                     xpos = scrollx - blit.source_width;
  1338.                     xpos < blit.clip_right;
  1339.                     xpos += blit.source_width
  1340.                 ){
  1341.                     draw( xpos,ypos );
  1342.                 }
  1343.             }
  1344.         }
  1345.         else if( rows == 1 ){ /* scrolling columns + horizontal scroll */
  1346.             int col = 0;
  1347.             int colwidth = blit.source_width / cols;
  1348.             int scrollx = rowscroll[0];
  1349.  
  1350.             if( scrollx < 0 ){
  1351.                 scrollx = blit.source_width - (-scrollx) % blit.source_width;
  1352.             }
  1353.             else {
  1354.                 scrollx = scrollx % blit.source_width;
  1355.             }
  1356.  
  1357.             blit.clip_top = top;
  1358.             blit.clip_bottom = bottom;
  1359.  
  1360.             while( col < cols ){
  1361.                 int cons = 1;
  1362.                 int scrolly = colscroll[col];
  1363.  
  1364.                  /* count consecutive columns scrolled by the same amount */
  1365.                 if( scrolly != TILE_LINE_DISABLED ){
  1366.                     while( col + cons < cols &&    colscroll[col + cons] == scrolly ) cons++;
  1367.  
  1368.                     if( scrolly < 0 ){
  1369.                         scrolly = blit.source_height - (-scrolly) % blit.source_height;
  1370.                     }
  1371.                     else {
  1372.                         scrolly %= blit.source_height;
  1373.                     }
  1374.  
  1375.                     blit.clip_left = col * colwidth + scrollx;
  1376.                     if (blit.clip_left < left) blit.clip_left = left;
  1377.                     blit.clip_right = (col + cons) * colwidth + scrollx;
  1378.                     if (blit.clip_right > right) blit.clip_right = right;
  1379.  
  1380.                     for(
  1381.                         ypos = scrolly - blit.source_height;
  1382.                         ypos < blit.clip_bottom;
  1383.                         ypos += blit.source_height
  1384.                     ){
  1385.                         draw( scrollx,ypos );
  1386.                     }
  1387.  
  1388.                     blit.clip_left = col * colwidth + scrollx - blit.source_width;
  1389.                     if (blit.clip_left < left) blit.clip_left = left;
  1390.                     blit.clip_right = (col + cons) * colwidth + scrollx - blit.source_width;
  1391.                     if (blit.clip_right > right) blit.clip_right = right;
  1392.  
  1393.                     for(
  1394.                         ypos = scrolly - blit.source_height;
  1395.                         ypos < blit.clip_bottom;
  1396.                         ypos += blit.source_height
  1397.                     ){
  1398.                         draw( scrollx - blit.source_width,ypos );
  1399.                     }
  1400.                 }
  1401.                 col += cons;
  1402.             }
  1403.         }
  1404.         else if( cols == 1 ){ /* scrolling rows + vertical scroll */
  1405.             int row = 0;
  1406.             int rowheight = blit.source_height / rows;
  1407.             int scrolly = colscroll[0];
  1408.             if( scrolly < 0 ){
  1409.                 scrolly = blit.source_height - (-scrolly) % blit.source_height;
  1410.             }
  1411.             else {
  1412.                 scrolly = scrolly % blit.source_height;
  1413.             }
  1414.             blit.clip_left = left;
  1415.             blit.clip_right = right;
  1416.             while( row < rows ){
  1417.                 int cons = 1;
  1418.                 int scrollx = rowscroll[row];
  1419.                 /* count consecutive rows scrolled by the same amount */
  1420.                 if( scrollx != TILE_LINE_DISABLED ){
  1421.                     while( row + cons < rows &&    rowscroll[row + cons] == scrollx ) cons++;
  1422.                     if( scrollx < 0){
  1423.                         scrollx = blit.source_width - (-scrollx) % blit.source_width;
  1424.                     }
  1425.                     else {
  1426.                         scrollx %= blit.source_width;
  1427.                     }
  1428.                     blit.clip_top = row * rowheight + scrolly;
  1429.                     if (blit.clip_top < top) blit.clip_top = top;
  1430.                     blit.clip_bottom = (row + cons) * rowheight + scrolly;
  1431.                     if (blit.clip_bottom > bottom) blit.clip_bottom = bottom;
  1432.                     for(
  1433.                         xpos = scrollx - blit.source_width;
  1434.                         xpos < blit.clip_right;
  1435.                         xpos += blit.source_width
  1436.                     ){
  1437.                         draw( xpos,scrolly );
  1438.                     }
  1439.                     blit.clip_top = row * rowheight + scrolly - blit.source_height;
  1440.                     if (blit.clip_top < top) blit.clip_top = top;
  1441.                     blit.clip_bottom = (row + cons) * rowheight + scrolly - blit.source_height;
  1442.                     if (blit.clip_bottom > bottom) blit.clip_bottom = bottom;
  1443.                     for(
  1444.                         xpos = scrollx - blit.source_width;
  1445.                         xpos < blit.clip_right;
  1446.                         xpos += blit.source_width
  1447.                     ){
  1448.                         draw( xpos,scrolly - blit.source_height );
  1449.                     }
  1450.                 }
  1451.                 row += cons;
  1452.             }
  1453.         }
  1454.     }
  1455. }
  1456.  
  1457. /***********************************************************************************/
  1458.  
  1459. #else // DECLARE
  1460. /*
  1461.     The following procedure body is #included several times by
  1462.     tilemap.c to implement a suite of tilemap_draw subroutines.
  1463.  
  1464.     The constants TILE_WIDTH and TILE_HEIGHT are different in
  1465.     each instance of this code, allowing arithmetic shifts to
  1466.     be used by the compiler instead of multiplies/divides.
  1467.  
  1468.     This routine should be fairly optimal, for C code, though of
  1469.     course there is room for improvement.
  1470.  
  1471.     It renders pixels one row at a time, skipping over runs of totally
  1472.     transparent tiles, and calling custom blitters to handle runs of
  1473.     masked/totally opaque tiles.
  1474. */
  1475.  
  1476. DECLARE( draw, (int xpos, int ypos),
  1477. {
  1478.     int tilemap_priority_code = blit.tilemap_priority_code;
  1479.     int x1 = xpos;
  1480.     int y1 = ypos;
  1481.     int x2 = xpos+blit.source_width;
  1482.     int y2 = ypos+blit.source_height;
  1483.  
  1484.     /* clip source coordinates */
  1485.     if( x1<blit.clip_left ) x1 = blit.clip_left;
  1486.     if( x2>blit.clip_right ) x2 = blit.clip_right;
  1487.     if( y1<blit.clip_top ) y1 = blit.clip_top;
  1488.     if( y2>blit.clip_bottom ) y2 = blit.clip_bottom;
  1489.  
  1490.     if( x1<x2 && y1<y2 ){ /* do nothing if totally clipped */
  1491.         DATA_TYPE *dest_baseaddr = xpos + (DATA_TYPE *)blit.screen->line[y1];
  1492.         DATA_TYPE *dest_next;
  1493.  
  1494.         int priority_bitmap_row_offset = priority_bitmap_line_offset*TILE_HEIGHT;
  1495.         UINT8 *priority_bitmap_baseaddr = xpos + (UINT8 *)priority_bitmap->line[y1];
  1496.         UINT8 *priority_bitmap_next;
  1497.  
  1498.         int priority = blit.tile_priority;
  1499.         const DATA_TYPE *source_baseaddr;
  1500.         const DATA_TYPE *source_next;
  1501.         const UINT8 *mask_baseaddr;
  1502.         const UINT8 *mask_next;
  1503.  
  1504.         int c1;
  1505.         int c2; /* leftmost and rightmost visible columns in source tilemap */
  1506.         int y; /* current screen line to render */
  1507.         int y_next;
  1508.  
  1509.         /* convert screen coordinates to source tilemap coordinates */
  1510.         x1 -= xpos;
  1511.         y1 -= ypos;
  1512.         x2 -= xpos;
  1513.         y2 -= ypos;
  1514.  
  1515.         source_baseaddr = (DATA_TYPE *)blit.pixmap->line[y1];
  1516.         mask_baseaddr = blit.bitmask->line[y1];
  1517.  
  1518.         c1 = x1/TILE_WIDTH; /* round down */
  1519.         c2 = (x2+TILE_WIDTH-1)/TILE_WIDTH; /* round up */
  1520.  
  1521.         y = y1;
  1522.         y_next = TILE_HEIGHT*(y1/TILE_HEIGHT) + TILE_HEIGHT;
  1523.         if( y_next>y2 ) y_next = y2;
  1524.  
  1525.         {
  1526.             int dy = y_next-y;
  1527.             dest_next = dest_baseaddr + dy*blit.dest_line_offset;
  1528.             priority_bitmap_next = priority_bitmap_baseaddr + dy*priority_bitmap_line_offset;
  1529.             source_next = source_baseaddr + dy*blit.source_line_offset;
  1530.             mask_next = mask_baseaddr + dy*blit.mask_line_offset;
  1531.         }
  1532.  
  1533.         for(;;){
  1534.             int row = y/TILE_HEIGHT;
  1535.             UINT8 *mask_data = blit.mask_data_row[row];
  1536.             UINT8 *priority_data = blit.priority_data_row[row];
  1537.  
  1538.             int tile_type;
  1539.             int prev_tile_type = TILE_TRANSPARENT;
  1540.  
  1541.             int x_start = x1;
  1542.             int x_end;
  1543.  
  1544.             int column;
  1545.             for( column=c1; column<=c2; column++ ){
  1546.                 if( column==c2 || priority_data[column]!=priority )
  1547.                     tile_type = TILE_TRANSPARENT;
  1548.                 else
  1549.                     tile_type = mask_data[column];
  1550.  
  1551.                 if( tile_type!=prev_tile_type ){
  1552.                     x_end = column*TILE_WIDTH;
  1553.                     if( x_end<x1 ) x_end = x1;
  1554.                     if( x_end>x2 ) x_end = x2;
  1555.  
  1556.                     if( prev_tile_type != TILE_TRANSPARENT ){
  1557.                         if( prev_tile_type == TILE_MASKED ){
  1558.                             int count = (x_end+7)/8 - x_start/8;
  1559.                             const UINT8 *mask0 = mask_baseaddr + x_start/8;
  1560.                             const DATA_TYPE *source0 = source_baseaddr + (x_start&0xfff8);
  1561.                             DATA_TYPE *dest0 = dest_baseaddr + (x_start&0xfff8);
  1562.                             UINT8 *pmap0 = priority_bitmap_baseaddr + (x_start&0xfff8);
  1563.                             int i = y;
  1564.                             for(;;){
  1565.                                 memcpybitmask( dest0, source0, mask0, count );
  1566.                                 memsetbitmask8( pmap0, tilemap_priority_code, mask0, count );
  1567.                                 if( ++i == y_next ) break;
  1568.  
  1569.                                 dest0 += blit.dest_line_offset;
  1570.                                 source0 += blit.source_line_offset;
  1571.                                 mask0 += blit.mask_line_offset;
  1572.                                 pmap0 += priority_bitmap_line_offset;
  1573.                             }
  1574.                         }
  1575.                         else { /* TILE_OPAQUE */
  1576.                             int num_pixels = x_end - x_start;
  1577.                             DATA_TYPE *dest0 = dest_baseaddr+x_start;
  1578.                             const DATA_TYPE *source0 = source_baseaddr+x_start;
  1579.                             UINT8 *pmap0 = priority_bitmap_baseaddr + x_start;
  1580.                             int i = y;
  1581.                             for(;;){
  1582.                                 memcpy( dest0, source0, num_pixels*sizeof(DATA_TYPE) );
  1583.                                 memset( pmap0, tilemap_priority_code, num_pixels );
  1584.                                 if( ++i == y_next ) break;
  1585.  
  1586.                                 dest0 += blit.dest_line_offset;
  1587.                                 source0 += blit.source_line_offset;
  1588.                                 pmap0 += priority_bitmap_line_offset;
  1589.                             }
  1590.                         }
  1591.                     }
  1592.                     x_start = x_end;
  1593.                 }
  1594.  
  1595.                 prev_tile_type = tile_type;
  1596.             }
  1597.  
  1598.             if( y_next==y2 ) break; /* we are done! */
  1599.  
  1600.             priority_bitmap_baseaddr = priority_bitmap_next;
  1601.             dest_baseaddr = dest_next;
  1602.             source_baseaddr = source_next;
  1603.             mask_baseaddr = mask_next;
  1604.  
  1605.             y = y_next;
  1606.             y_next += TILE_HEIGHT;
  1607.  
  1608.             if( y_next>=y2 ){
  1609.                 y_next = y2;
  1610.             }
  1611.             else {
  1612.                 dest_next += blit.dest_row_offset;
  1613.                 priority_bitmap_next += priority_bitmap_row_offset;
  1614.                 source_next += blit.source_row_offset;
  1615.                 mask_next += blit.mask_row_offset;
  1616.             }
  1617.         } /* process next row */
  1618.     } /* not totally clipped */
  1619. })
  1620.  
  1621. DECLARE( draw_opaque, (int xpos, int ypos),
  1622. {
  1623.     int tilemap_priority_code = blit.tilemap_priority_code;
  1624.     int x1 = xpos;
  1625.     int y1 = ypos;
  1626.     int x2 = xpos+blit.source_width;
  1627.     int y2 = ypos+blit.source_height;
  1628.     /* clip source coordinates */
  1629.     if( x1<blit.clip_left ) x1 = blit.clip_left;
  1630.     if( x2>blit.clip_right ) x2 = blit.clip_right;
  1631.     if( y1<blit.clip_top ) y1 = blit.clip_top;
  1632.     if( y2>blit.clip_bottom ) y2 = blit.clip_bottom;
  1633.  
  1634.     if( x1<x2 && y1<y2 ){ /* do nothing if totally clipped */
  1635.         UINT8 *priority_bitmap_baseaddr = xpos + (UINT8 *)priority_bitmap->line[y1];
  1636.         int priority_bitmap_row_offset = priority_bitmap_line_offset*TILE_HEIGHT;
  1637.  
  1638.         int priority = blit.tile_priority;
  1639.         DATA_TYPE *dest_baseaddr = xpos + (DATA_TYPE *)blit.screen->line[y1];
  1640.         DATA_TYPE *dest_next;
  1641.         const DATA_TYPE *source_baseaddr;
  1642.         const DATA_TYPE *source_next;
  1643.  
  1644.         int c1;
  1645.         int c2; /* leftmost and rightmost visible columns in source tilemap */
  1646.         int y; /* current screen line to render */
  1647.         int y_next;
  1648.  
  1649.         /* convert screen coordinates to source tilemap coordinates */
  1650.         x1 -= xpos;
  1651.         y1 -= ypos;
  1652.         x2 -= xpos;
  1653.         y2 -= ypos;
  1654.  
  1655.         source_baseaddr = (DATA_TYPE *)blit.pixmap->line[y1];
  1656.  
  1657.         c1 = x1/TILE_WIDTH; /* round down */
  1658.         c2 = (x2+TILE_WIDTH-1)/TILE_WIDTH; /* round up */
  1659.  
  1660.         y = y1;
  1661.         y_next = TILE_HEIGHT*(y1/TILE_HEIGHT) + TILE_HEIGHT;
  1662.         if( y_next>y2 ) y_next = y2;
  1663.  
  1664.         {
  1665.             int dy = y_next-y;
  1666.             dest_next = dest_baseaddr + dy*blit.dest_line_offset;
  1667.             source_next = source_baseaddr + dy*blit.source_line_offset;
  1668.         }
  1669.  
  1670.         for(;;){
  1671.             int row = y/TILE_HEIGHT;
  1672.             UINT8 *priority_data = blit.priority_data_row[row];
  1673.  
  1674.             int tile_type;
  1675.             int prev_tile_type = TILE_TRANSPARENT;
  1676.  
  1677.             int x_start = x1;
  1678.             int x_end;
  1679.  
  1680.             int column;
  1681.             for( column=c1; column<=c2; column++ ){
  1682.                 if( column==c2 || priority_data[column]!=priority )
  1683.                     tile_type = TILE_TRANSPARENT;
  1684.                 else
  1685.                     tile_type = TILE_OPAQUE;
  1686.  
  1687.                 if( tile_type!=prev_tile_type ){
  1688.                     x_end = column*TILE_WIDTH;
  1689.                     if( x_end<x1 ) x_end = x1;
  1690.                     if( x_end>x2 ) x_end = x2;
  1691.  
  1692.                     if( prev_tile_type != TILE_TRANSPARENT ){
  1693.                         /* TILE_OPAQUE */
  1694.                         int num_pixels = x_end - x_start;
  1695.                         DATA_TYPE *dest0 = dest_baseaddr+x_start;
  1696.                         UINT8 *pmap0 = priority_bitmap_baseaddr+x_start;
  1697.                         const DATA_TYPE *source0 = source_baseaddr+x_start;
  1698.                         int i = y;
  1699.                         for(;;){
  1700.                             memcpy( dest0, source0, num_pixels*sizeof(DATA_TYPE) );
  1701.                             memset( pmap0, tilemap_priority_code, num_pixels );
  1702.                             if( ++i == y_next ) break;
  1703.  
  1704.                             dest0 += blit.dest_line_offset;
  1705.                             pmap0 += priority_bitmap_line_offset;
  1706.                             source0 += blit.source_line_offset;
  1707.                         }
  1708.                     }
  1709.                     x_start = x_end;
  1710.                 }
  1711.  
  1712.                 prev_tile_type = tile_type;
  1713.             }
  1714.  
  1715.             if( y_next==y2 ) break; /* we are done! */
  1716.  
  1717.             priority_bitmap_baseaddr += priority_bitmap_row_offset;
  1718.             dest_baseaddr = dest_next;
  1719.             source_baseaddr = source_next;
  1720.  
  1721.             y = y_next;
  1722.             y_next += TILE_HEIGHT;
  1723.  
  1724.             if( y_next>=y2 ){
  1725.                 y_next = y2;
  1726.             }
  1727.             else {
  1728.                 dest_next += blit.dest_row_offset;
  1729.                 source_next += blit.source_row_offset;
  1730.             }
  1731.         } /* process next row */
  1732.     } /* not totally clipped */
  1733. })
  1734.  
  1735. #undef TILE_WIDTH
  1736. #undef TILE_HEIGHT
  1737. #undef DATA_TYPE
  1738. #undef memcpybitmask
  1739. #undef DECLARE
  1740.  
  1741. #endif /* DECLARE */
  1742.